﻿#ifndef FFMPEGTHREAD_H
#define FFMPEGTHREAD_H

/************************************************************************
  *Copyright(C) ZXT 1174110975@qq.com
  *FileName: ffmpegthread.h
  *Author: 周新童
  *Date: 2022-01-11
  *Description: 1. 解码子线程。对输入资源进行解析、资源分配，视音频数据解码播放
                2. 包含直接解码以及队列解码两种方式
                直接解码：无论视频还是音频帧，拿到就正常解码处理送去渲染或声音播放
                队列解码：只负责解析到avPacket，视频、音频packet添加到各自队列
                        各自队列负责自己的帧解码以及之后的渲染或声音播放
                3. 支持ffmpeg水印等功能，待继续完善
*************************************************************************/

#include <QObject>
#include <QThread>
#include <QDebug>
#include <QTimer>
#include <QDateTime>
#include <QImage>
#include <QtMultimedia>
#include <QAudioOutput>
#include "ffmpeghead.h"
#include "ffmpegsynclist.h"

#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss:zzz"))

class FFmpegThread : public QThread
{
    Q_OBJECT
public:
    explicit FFmpegThread(QObject *parent = 0);
    ~FFmpegThread();

    //解码同步线程定义成友元类
    friend class FFmpegSyncList;

    //解析输入对象，初始化设置并返回结果
    bool processInput();
    void setOption();
    bool setInput();
    bool setVideo();
    bool setAudio();
    bool setAudioDevice(int sampleRate, int sampleSize, int channelCount);
    bool setOther();
    void freeResources();
    void freeAudio();
    void freeSync();

    //添加水印功能
    bool setFilter();

    //音视频数据包的解码处理
    void transVideoPacket(AVPacket *packet);
    void transAudioPacket(AVPacket *packet);
    void decodeVideoPacket(AVPacket *packet);
    void decodeAudioPacket(AVPacket *packet);

    //播放延时计算
    qint64 getPacketPts(AVPacket *packet);
    qint64 calcDelayTime(AVFormatContext *formatCtx, AVPacket *packet);
    void timeDelay(AVFormatContext *formatCtx, AVPacket *packet);

    //播放控制
    void setPlayUrl(const QString &playUrl);
    void startPlay();
    void stopPlay();
    void pausePlay();
    void nextPlay();

    //播放设置以及状态的获取
    int  getLength();
    void setAudioEnable(bool enable);
    void setPlaySpeed(int level);
    void setPlayPosition(qint64 position);
    void setPositionEnable(bool enable);
    int  getVideoWidth();
    int  getVideoHeight();
    void setEnableSyncList(bool enable);

    //文件保存
    void initSaveFile();
    void startSaveData(AVPacket *packet);
    void stopSaveData();
    void startSaveFile(const QString &path);
    void stopSaveFile();

protected:
    //线程执行函数
    void run();

signals:
    void sendImage(const QImage &image);
    void sendFrame(AVFrame *frame);
    void sendPlayStart();
    void sendPlayError();
    void sendPlayFinish();
    void sendPlayPosition(int sec);

private:
    volatile bool isRun;              //线程开关标志位
    volatile bool isPause;            //播放暂停标志位
    volatile bool isSpeed;            //倍速播放标志位
    volatile bool isSendPosition;     //返回播放进度标志位
    bool isFirstInit;                 //首次初始化标志位
    bool isNetUrl;                    //网络地址
    bool isUsbCamera;                 //USB设备
    bool isPlayAudio;                 //启用音频
    bool audioDeviceOk;               //音频设备正常
    bool switchSpeed;                 //切换速度
    bool enableFilter;                //开启水印功能
    bool enableSyncList;              //使用同步队列方式
    int  lastSpeedLevel;              //上次倍速级别

    QString playUrl;                  //播放地址
    int frameTime;                    //当前帧播放时间
    volatile double playSpeed;        //解码间隔时间 pts方式
    volatile double lastPlaySpeed;    //解码间隔时间 pts方式

    volatile bool isSave;             //开启文件保存
    bool isFirstInitSave;             //首次初始化文件保存
    bool initSaveOk;                  //初始化保存信息
    bool saveStatus;                  //开始或结束保存
    int  saveCount;                   //保存数据计数
    QString saveFileName;             //文件保存名称
    AVFormatContext *formatOut;       //输出文件格式对象

    double frameRate;                 //帧率
    int duration;                     //时长 单位秒
    int frameFinish;                  //一帧完成
    int videoWidth;                   //视频宽度
    int videoHeight;                  //视频高度
    int videoStreamIndex;             //视频流索引
    int audioStreamIndex;             //音频流索引

    qint64 startPrecessTime;          //数据处理开始时间
    qint64 pauseTime;                 //点击暂停时间
    qint64 videoFirstPts;             //首个视频包的pts
    qint64 audioFirstPts;             //首个音频包的pts
    uint8_t *videoData;               //解码后图片数据
    uint8_t *audioData;               //解码后音频数据
    AVPacket *avPacket;               //包对象
    AVFrame *videoFrame;              //视频帧对象
    AVFrame *videoFrameDst;           //视频帧转换后的对象
    AVFrame *audioFrame;              //音频帧对象
    AVFormatContext *avFormatContext; //格式对象
    AVCodecContext *videoCodecCtx;    //视频解码器对象
    AVCodecContext *audioCodecCtx;    //音频解码器对象
    SwsContext *videoSwsCtx;          //视频数据转换对象
    SwrContext *audioSwrCtx;          //音频数据转换对象重采样
    AVDictionary *options;            //参数对象
    AVCodec *videoDecoder;            //视频解码器
    AVCodec *audioDecoder;            //音频解码器
    FFmpegSyncList *videoSync;        //视频同步队列
    FFmpegSyncList *audioSync;        //音频同步队列

    QAudioOutput *audioOutput;        //音频播放对象
    QIODevice *audioDevice;           //音频IO设备

    AVFrame *videoFilterFrame;        //视频帧完成过滤后的对象
    AVFilterGraph *filter_graph;      //过滤器graph
    AVFilterContext *buffersink_ctx;  //过滤器上下文
    AVFilterContext *buffersrc_ctx;
    AVFilterInOut *filterOutputs;     //过滤器IO设置
    AVFilterInOut *filterInputs;
};

#endif // FFMPEGTHREAD_H
